package com.aios.service.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.print.attribute.standard.DateTimeAtCompleted;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import com.aios.dao.SwitchMapper;
import com.aios.dao.SwitchPanelMapper;
import com.aios.entity.Switch;
import com.aios.entity.SwitchPanel;
import com.aios.entity.mapper.SwitchTimer;
import com.aios.service.ExistValidationEnum;
import com.aios.exception.AiosStatusUpdateException;
import com.aios.service.SwitchService;
import com.aios.util.GuidGenerator;
import com.aios.util.AiosAccessUtil;
import com.aios.util.HttpClientAdaptor.HttpClientResponse;
import com.aios.util.HttpClientExecuter;
import com.aios.util.JsonConvertor;

@Service("switchService")
public class SwitchServiceImpl extends AbstractService implements SwitchService {

	private static Logger logger = Logger.getLogger(SwitchServiceImpl.class);
	private List<SwitchTimer> switchTimerList;
	private List<Switch> currentSwitchStateList;
	private List<Switch> newSwitchConfig,recheckConfig;
	private static final int MAX_MIN=1440;
	private String tmp_PanelId="";
	
	@Autowired
	private SwitchMapper switchMapper;
	@Autowired
	private SwitchPanelMapper switchPanelMapper;

	@Override
	public List<Switch> findAll() {
		return null;
	}

	@Override
	public List<Switch> findAllNotDisabled() {
		return null;
	}

	@Override
	public List<Switch> findAllDisabled() {
		return null;
	}

	@Override
	public Switch findById(String id) {
		return switchMapper.selectByPrimaryKey(id);
	}

	@Override
	public int save(Switch entity) {
		return 0;
	}

	@Override
	public int update(Switch entity) {
		return 0;
	}

	@Override
	public int delete(Switch id) {
		return 0;
	}

	@Override
	public int delete(String id) {
		return 0;
	}

	@Override
	public int save(Switch entity, String userId) {
		saveAddSettings(entity, userId);
		entity.setId(GuidGenerator.switchKey());
		return save(entity);
	}

	@Override
	public int update(Switch entity, String userId) {
		saveEditSettings(entity, userId);
		return switchMapper.updateByPrimaryKeySelective(entity);
	}

	@Override
	public List<Switch> findBySwitchPanel(String id) {
		return switchMapper.findBySwitchPanel(id);
	}

	@Override
	public List<Switch> findAllBySwitchPanelId(String id) {
		return switchMapper.findAllBySwitchPanelId(id);
	}

	@Override
	public List<Switch> findByUserId(String id) {
		return null;
	}

	public List<Switch> viewCurrentSwitchStatus(String panelId) {
		return switchStatus(panelId);
	}

	public List<Switch> switchStatus(String panelId) {
		
		SwitchPanel switchPanel = switchPanelMapper.findById(panelId);

		if (switchPanel == null) {
			return null;
		}

		HttpClientResponse response = HttpClientExecuter
				.getAiosControllerResponse(switchPanel.getProtocol(), switchPanel.getUrl(),
						switchPanel.getHttpPort(), switchPanel.getUserName(),
						switchPanel.getUserPassword(),
						AiosAccessUtil.STATUS_URI, true);
		//System.out.println(response.getResponseText());

		if (response.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK) {

			try {
				List<Switch> switchList = switchMapper.findAllBySwitchPanelId(panelId);

				Map<String, String> map = JsonConvertor.convertAiosStateResponse(response.getResponseText());

				if (switchList != null && map != null) {
					for (Switch s : switchList) {
						s.setCurrentState(map.get(s.getControllerReceiver()));
					}
				} else {
					logger.error("data not recieved from DB or AIOS");
				}

				return switchList;

			} catch (AiosStatusUpdateException e) {
				logger.error(e);
			}

		}

		return null;

	}

	public boolean changeSwitchStatus(String panelId, String switchId) {

		Switch switchButton = switchMapper.selectByPrimaryKey(switchId);
		SwitchPanel switchPanel = switchPanelMapper.findById(panelId);

		if (switchButton == null || switchPanel == null) {
			return true;
		}

		HttpClientResponse response = HttpClientExecuter
				.getAiosChangeOperation(switchPanel.getProtocol(), switchPanel.getUrl(),
						switchPanel.getHttpPort(), switchPanel.getUserName(),
						switchPanel.getUserPassword(),
						AiosAccessUtil.CHANGE_URI,
						switchButton.getControllerParameter(), true);

		if (response.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK) {
			return true;
		}

		return false;
	}

	//@Scheduled(cron = "0/60 * * * * ?")
	// @Scheduled(cron="0 0/5 * * * *")
	@Scheduled(cron = "0 03,08,13,18,23,28,33,38,43,48,53,58 * * * ?")
	public void switchTrigger() {
		//System.out.println("cron enter");
		//switchStatus("00011");
		Calendar c = Calendar.getInstance();
		 int min = getCurrentMinFromMidNight();
		int day = c.get(Calendar.DAY_OF_WEEK);
		int max = min +5;
		newSwitchConfig = new ArrayList<Switch>();
		

		try {
			//System.out.println("Min:"+min);
			if(max>MAX_MIN){
				min=0;
				switchTimerList = findByDayAndTime(day, min, min+3);
			}else{
				switchTimerList = findByDayAndTime(day-1, min, min+5);
			}

			if (switchTimerList != null) {
				logSwitchStatus(switchTimerList,"Before Timer Execute ");
				findCurrentStatus(switchTimerList);
				if (newSwitchConfig.size()>0) {
					for (int i = 0; i < newSwitchConfig.size(); i++) {
						
						changeSwitchStatus(newSwitchConfig.get(i)
								.getSwitchPanelId(), newSwitchConfig.get(i)
								.getId()); // switchList.get(0).getSwitchPanelId(),switchList.get(0).getId());
						Thread.sleep(4000);
						logger.info(" Timer change-> Switch :"+newSwitchConfig.get(i).getId()+" changed on "+Calendar.getInstance().getTime()+"\n");
						//System.out.println(newSwitchConfig.get(i).getId()+":"+Calendar.getInstance().getTime());
					}
				}
				Thread.sleep(10000);
				newSwitchConfig.clear();
				for (int j = 0; j < 3; j++) {
				recheckConfig = new ArrayList<Switch>();
				refindCurrentStatus(switchTimerList);	
				if (!recheckConfig.isEmpty()) {
					checkSwitchStatus(recheckConfig,"Before Rerun ");
						for (int i = 0; i < recheckConfig.size(); i++) {

							changeSwitchStatus(recheckConfig.get(i)
									.getSwitchPanelId(), recheckConfig.get(i)
									.getId()); // switchList.get(0).getSwitchPanelId(),switchList.get(0).getId());
							logger.info("Rerun Timer change-> Switch :"+recheckConfig.get(i).getId()+" changed on "+Calendar.getInstance().getTime()+"\n");
							Thread.sleep(4000);//System.out.println(recheckConfig.get(i).getId()+":"+Calendar.getInstance().getTime());
						}
					}
				Thread.sleep(5000);
				}
				logSwitchStatus(switchTimerList,"After Timer Execute ");
				//System.out.println("Time:"+Calendar.getInstance().getTime());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	public int getCurrentMinFromMidNight() {

		Calendar c = Calendar.getInstance();
		long now = c.getTimeInMillis();
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		long passed = now - c.getTimeInMillis();
		long time = passed / (1000 * 60);
		int min = (int) time;

		return min;

	}

	@Override
	public ExistValidationEnum nameExistValidation(String id, String name,
			String userId) {
		List<Switch> list = switchMapper.findByNameNotWithId(id, name, userId);
		if (list == null || list.size() == 0) {

			return ExistValidationEnum.NOT_EXIST;
		} else if (list.size() == 1) {

			return ExistValidationEnum.EXIST;
		} else {

			return ExistValidationEnum.MULTIPLE_EXIST;
		}
	}

	@Override
	public List<SwitchTimer> findByDayAndTime(int day, int min, int max) {
		// System.out.println(day+","+min+","+max);
		return switchMapper.findByDayTimeAndTime(day, min, max);
	}

	public void findCurrentStatus(List<SwitchTimer> sl) {

		for (int i = 0; i < sl.size(); i++) {
			currentSwitchStateList = switchStatus(sl.get(i).getSwitchPanelID());
			
			
			for (int j = 0; j < currentSwitchStateList.size(); j++) {
				if (sl.get(i).getControllerReceiver().equals(currentSwitchStateList.get(j).getControllerReceiver())) {

					if (!sl.get(i).getSwitchSetting().equals(currentSwitchStateList.get(j).getSwitchSetting())) {
						Switch sw = new Switch();
						sw.setSwitchPanelId(sl.get(i).getSwitchPanelID());
						sw.setId(sl.get(i).getSwitchID());
						newSwitchConfig.add(sw);
						if(sl.get(i).getSwitchSetting().equals("ON_OFF")) {
							if(currentSwitchStateList.get(j).getSwitchSetting().equals("ON")) {
								sl.get(i).setSwitchSetting("OFF");
							}
							else if(currentSwitchStateList.get(j).getSwitchSetting().equals("OFF")) {
								sl.get(i).setSwitchSetting("ON");
							}
						}
							
						
						
						break;
					}

				}
			}
		}

	}
	public void refindCurrentStatus(List<SwitchTimer> sl) {
			//currentSwitchStateList.clear();
		for (int i = 0; i < sl.size(); i++) {
			currentSwitchStateList = switchStatus(sl.get(i).getSwitchPanelID());
			
			for (int j = 0; j < currentSwitchStateList.size(); j++) {
				if (sl.get(i).getControllerReceiver().equals(currentSwitchStateList.get(j).getControllerReceiver())) {
					if (!sl.get(i).getSwitchSetting().equals(currentSwitchStateList.get(j).getSwitchSetting())) {
						Switch sw = new Switch();
						sw.setSwitchPanelId(sl.get(i).getSwitchPanelID());
						sw.setId(sl.get(i).getSwitchID());
						recheckConfig.add(sw);
						break;
					}

				}
			}
		}

	}
	public void logSwitchStatus(List<SwitchTimer> sl,String status){
		
		for (int i = 0; i < sl.size(); i++) {
			if(!tmp_PanelId.equals(sl.get(i).getSwitchPanelID())){
			tmp_PanelId=sl.get(i).getSwitchPanelID();
			SwitchPanel switchPanel = switchPanelMapper.findById(tmp_PanelId);
			String url=AiosAccessUtil.PROTOCOL+AiosAccessUtil.PROTOCOL_SEPERATOR+switchPanel.getUrl()+AiosAccessUtil.PORT_SEPERATOR+switchPanel.getHttpPort()+AiosAccessUtil.STATUS_URI;
			HttpClientResponse response = HttpClientExecuter
					.getAiosControllerResponse(switchPanel.getProtocol(), switchPanel.getUrl(),
							switchPanel.getHttpPort(), switchPanel.getUserName(),
							switchPanel.getUserPassword(),
							AiosAccessUtil.STATUS_URI, true);
			//System.out.println(response.getResponseText());
				logger.info(status+"NB202 request from:"+tmp_PanelId+":"+url);
				logger.info(status+"NB202 response from:"+tmp_PanelId+"\n"+response.getResponseText());
			}
		}
		tmp_PanelId="";
	}

public void checkSwitchStatus(List<Switch> sl,String status){
		
		for (int i = 0; i < sl.size(); i++) {
			if(!tmp_PanelId.equals(sl.get(i).getSwitchPanelId())){
			tmp_PanelId=sl.get(i).getSwitchPanelId();
			SwitchPanel switchPanel = switchPanelMapper.findById(tmp_PanelId);
			String url=AiosAccessUtil.PROTOCOL+AiosAccessUtil.PROTOCOL_SEPERATOR+switchPanel.getUrl()+AiosAccessUtil.PORT_SEPERATOR+switchPanel.getHttpPort()+AiosAccessUtil.STATUS_URI;
			HttpClientResponse response = HttpClientExecuter
					.getAiosControllerResponse(switchPanel.getProtocol(), switchPanel.getUrl(),
							switchPanel.getHttpPort(), switchPanel.getUserName(),
							switchPanel.getUserPassword(),
							AiosAccessUtil.STATUS_URI, true);
			//System.out.println(response.getResponseText());
				logger.info(status+"NB202 request from:"+tmp_PanelId+":"+url);
				logger.info(status+"NB202 response from:"+tmp_PanelId+"\n"+response.getResponseText());
			}
		}
		tmp_PanelId="";
	}
	public List<Switch> getCurrentSwitchStateList() {
		return currentSwitchStateList;
	}

	public void setCurrentSwitchStateList(List<Switch> currentSwitchStateList) {
		this.currentSwitchStateList = currentSwitchStateList;
	}

	public List<Switch> getNewSwitchConfig() {
		return newSwitchConfig;
	}

	public void setNewSwitchConfig(List<Switch> newSwitchConfig) {
		this.newSwitchConfig = newSwitchConfig;
	}

	public List<SwitchTimer> getSwitchTimerList() {
		return switchTimerList;
	}

	public void setSwitchTimerList(List<SwitchTimer> switchTimerList) {
		this.switchTimerList = switchTimerList;
	}
}
